package com.rookie.im.server.utils;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.rabbitmq.client.*;
import com.rookie.im.codec.proto.Message;
import com.rookie.im.domain.enums.CommandType;
import com.rookie.im.domain.utils.Constants;
import com.rookie.im.server.config.AppConfig;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeoutException;

@Slf4j
public class RabbitManager {
    private static final Object lock = new Object();
    private static ConnectionFactory factory = null;
    private static Connection connection = null;
    private static ConcurrentHashMap<String, Channel> channelHashMap = new ConcurrentHashMap<>();

    public static Channel getChannel(String channelName) {
        return channelHashMap.computeIfAbsent(channelName, k -> {
            try {
                return getConnection().createChannel();
            } catch (IOException e) {
                throw new RuntimeException("Failed to create a channel for " + k, e);
            }
        });
    }
    public static Connection getConnection() {
        synchronized (lock) {
            if (connection == null) {
                try {
                    connection = factory.newConnection();
                } catch (IOException | TimeoutException e) {
                    throw new RuntimeException("Failed to create connection: " + e);
                }
            }
        }
        return connection;
    }
    public static void init(AppConfig.Rabbitmq rabbitmq) {
        synchronized (lock) {
            if (factory == null) {
                factory = new ConnectionFactory();
                factory.setHost(rabbitmq.getHost());
                factory.setPort(rabbitmq.getPort());
                factory.setUsername(rabbitmq.getUsername());
                factory.setPassword(rabbitmq.getPassword());
                factory.setVirtualHost(rabbitmq.getVirtualHost());
            }
        }
    }

    public static void publish(Message message) {
        int command = message.getMessageHead().getCommand();
        String channelName = Constants.RabbitConstants.Im2MessageService;
        switch (CommandType.genCommandType(command)) {
            case SYSTEM:
                channelName = Constants.RabbitConstants.Im2SystemService;
                break;
            case USER:
                channelName = Constants.RabbitConstants.Im2UserService;
                break;
            case MESSAGE:
            default:
//                channelName = Constants.RabbitConstants.Im2MessageService;
        }
        try {
            Channel channel = getChannel(channelName);
            JSONObject json = (JSONObject) JSON.toJSON(message.getMessagePack());
            json.put("command", message.getMessageHead().getCommand());
            json.put("clientType", message.getMessageHead().getClientType());
            json.put("imei", message.getMessageHead().getImei());
            json.put("appId", message.getMessageHead().getAppId());
            log.info("push msg to {}: {}", channelName, json);
            channel.basicPublish(channelName, "", null, json.toJSONString().getBytes());
        } catch (IOException e) {
            log.error("mq推送异常: {}", e.getMessage());
        }
    }

    public static void reciver() {
        try {
            Channel channel = getChannel(Constants.RabbitConstants.MessageService2Im);
            channel.queueDeclare(Constants.RabbitConstants.MessageService2Im, true, false, false, null);
            channel.queueBind(Constants.RabbitConstants.MessageService2Im, Constants.RabbitConstants.MessageService2Im, "");
            channel.basicConsume(Constants.RabbitConstants.MessageService2Im, false,
                    new DefaultConsumer(channel) {
                        @Override
                        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                            log.info("接收到服务端发来的消息：{}", new String(body));
                        }
                    });
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
